package xyz.hzxiao.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Configuration;
import xyz.hzxiao.handler.init.WebSocketInitChannelHandler;

import java.net.InetSocketAddress;

/**
 * DemoSocket端点
 *
 * @author ：FuXx
 * @className : xyz.hzxiao.server.DemoWebSocketEndpoint
 * @since ：2025/1/10
 */
@Configuration
public class DemoWebSocketEndpoint implements InitializingBean, DisposableBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoWebSocketEndpoint.class);

    /**
     * 主线程组数量
     */
    final int PROCESSOR_COUNT = Runtime.getRuntime().availableProcessors();

    /**
     * 工作线程组数量
     */
    final int WORKER_GROUP_SIZE = PROCESSOR_COUNT * 8;

    /**
     * 监听地址
     */
    final String HOST = "0.0.0.0";

    /**
     * 监听端口
     */
    final int PORT = 8292;

    /**
     * 监听队列长度
     */
    final int BACKLOG = 128;

    /**
     * 接收缓冲区大小
     */
    final int RECEIVE_BUFFER_SIZE = BACKLOG * 1024;

    /**
     * 发送缓冲区大小
     */
    final int SEND_BUFFER_SIZE = 1024 * 1024;

    /**
     * 写缓冲区高水位线
     */
    final int WRITE_BUFFER_HIGH_WATER_MARK = SEND_BUFFER_SIZE / 2;

    /**
     * 主线程组
     */
    private NioEventLoopGroup bossGroup;

    /**
     * 工作线程组
     */
    private NioEventLoopGroup workGroup;

    /**
     * 绑定的端口
     */
    private ChannelFuture channelFuture;

    /**
     * Invoked by the containing {@code BeanFactory} on destruction of a bean.
     *
     */
    @Override
    public void destroy() {
        this.workGroup.shutdownGracefully();
        this.bossGroup.shutdownGracefully();
        this.channelFuture.channel().closeFuture();
        LOGGER.info("Netty Server Is Destroy");
    }

    /**
     * Invoked by the containing {@code BeanFactory} after it has set all bean properties
     * and satisfied {@code BeanFactoryAware}, {@code ApplicationContextAware} etc.
     * <p>This method allows the bean instance to perform validation of its overall
     * configuration and final initialization when all bean properties have been set.
     *
     */
    @Override
    public void afterPropertiesSet() {
        startEndpoint();
    }

    /**
     * 启动Netty服务端
     */
    private void startEndpoint() {
        this.bossGroup = new NioEventLoopGroup(PROCESSOR_COUNT);
        this.workGroup = new NioEventLoopGroup(WORKER_GROUP_SIZE);
        InetSocketAddress address = new InetSocketAddress(HOST, PORT);
        this.channelFuture = new ServerBootstrap()
                .group(bossGroup, workGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new WebSocketInitChannelHandler())
                .localAddress(address)
                .option(ChannelOption.SO_BACKLOG, BACKLOG)
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
                .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
                .childOption(ChannelOption.SO_RCVBUF, RECEIVE_BUFFER_SIZE)
                .childOption(ChannelOption.SO_SNDBUF, SEND_BUFFER_SIZE)
                .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(WRITE_BUFFER_HIGH_WATER_MARK, SEND_BUFFER_SIZE))
                .bind(address);
        LOGGER.info("Netty Server Started on {}:{} Successful", HOST, PORT);
    }
}
